import java.net.MalformedURLException;
import java.net.URL;

import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.XmlRpcException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
import java.io.IOException;
import org.w3c.dom.Node;
/**
 * 
 */

/**
 * @author karthik
 *
 */
public class OpennebulaController extends CloudController {

	/* (non-Javadoc)
	 * @see CloudController#DeleteInstance(int)
	 */
	private XmlRpcClientConfigImpl config;
	private XmlRpcClient client;
	private URL url;
	private String session;
	/*private String microInstance;
	private String smallInstance;
	private String largeInstance;*/
	OpennebulaController(String u,String s) {
		
		/* Defining different instance types for Opennebula cloud abstracting out the concept of vm instance template.
		 * Micro instance gets 1 virtual core and 600 MB of RAM. Small and large instances get 1 virtual core, 1000 MB memory
		 * and 2 virtual core, 2000 MB memory respectively.  
		 */
		
		/* XMLRPC server for opennebula operates on the frontend. URL denotes the fqdn or ipaddress along with the port on which
		 * the XMLRPC server listens for client calls. 
		 */
		try {
		url = new URL(u);
		}
		catch(MalformedURLException e) {
			e.printStackTrace();		
			return;
		}
		/*Authentication and authorization for opennebula's XMLRPC server is handled through a session string, 
		 * generated from a combination of user id and password hash.
		 */
		session = s;
		config = new XmlRpcClientConfigImpl();
		config.setServerURL(url);
	    client = new XmlRpcClient();
	    client.setConfig(config);
		
	}
	
	@Override
	boolean deleteInstance(String InstanceId) {
		return false;
	}

	/* (non-Javadoc)
	 * @see CloudController#GetInstanceInfo(int)
	 */
	@Override
	String getInstanceInfo(String InstanceId) {
		Object[] params = new Object[]{new String(session), new Integer(InstanceId)};
        try {
        	Object[] result = (Object[])client.execute("one.vm.info",params);
        	if(!result[0].equals(null)) {
        		String result_s = (String)result[1];
        		return result_s;
        	}
        	return "ERROR_CALL";
        }
        catch (XmlRpcException e) {
			e.printStackTrace();
			return "ERROR_EXCEP";
		}
		
	}

	/* (non-Javadoc)
	 * @see CloudController#GetRunningInstances()
	 */
	@Override
	String getRunningInstances() {
		Object[] params = new Object[]{new String(session), new Integer(-1)};
        
        try {
        	Object[] result = (Object[])client.execute("one.vmpool.info",params);
        	if(!result[0].equals(null)) {
        		String result_s = (String)result[1];
        		return result_s;
        	}
        	return "ERROR_CALL";
        }
        catch (XmlRpcException e) {
			e.printStackTrace();
			return "ERROR_EXCEP";
		}
		
		
	}

	/* (non-Javadoc)
	 * @see CloudController#LaunchInstance(java.lang.String)
	 */
	@Override
	String launchInstance(String Img,String InstanceType) {
		microInstance = "NAME   = koushik_ubuntu CPU = 1 MEMORY = 600 " 
			+ "DISK   = [ source   = "+Img+", target   = \"sda\","
			+ "readonly = \"no\", DRIVER=qcow2] OS = [ ARCH = x86_64] NIC    = [ NETWORK = \"VM_LAN\" ] FEATURES=[ acpi=\"yes\" ]";
		smallInstance = "NAME   = koushik_ubuntu CPU = 1 MEMORY = 1000 " 
		+ "DISK   = [ source   = "+Img+", target   = \"sda\","
		+ "readonly = \"no\", DRIVER=qcow2] OS = [ ARCH = x86_64] NIC    = [ NETWORK = \"VM_LAN\" ] FEATURES=[ acpi=\"yes\" ]";
		largeInstance = "NAME   = koushik_ubuntu CPU = 2 MEMORY = 2000 " 
		+ "DISK   = [ source   = "+Img+", target   = \"sda\","
		+ "readonly = \"no\", DRIVER=qcow2] OS = [ ARCH = x86_64] NIC    = [ NETWORK = \"VM_LAN\" ] FEATURES=[ acpi=\"yes\" ]";
		String template = new String();
		
		if(InstanceType == "Large")
			template = largeInstance;
		else if(InstanceType == "Small")
			template = smallInstance;
		else 
			template = microInstance;
		Object[] params = new Object[]{new String(session), new String(template)};
        
        try {
        	Object[] result = (Object[])client.execute("one.vm.allocate",params);
        	if(!result[0].equals(null)) {
        		Integer result_vmid = (Integer)result[1];
        		return String.valueOf(result_vmid.intValue());
        	}
        	return String.valueOf(-1);
        }
        catch (XmlRpcException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return String.valueOf(-1);
		}
		
	}

	/* (non-Javadoc)
	 * @see CloudController#ShutdownInstance(int)
	 */
	@Override
	boolean shutdownInstance(String InstanceId) {
        
		Object[] params = new Object[]{new String(session),new String("shutdown"), new Integer(InstanceId)};
		try {
        	Object[] result = (Object[])client.execute("one.vm.action",params);
        	if(!result[0].equals(null)) {
        		String result_s = (String)result[1];
        		System.out.println(result_s);
        		return true;
        	}
        	return false;
        }
        catch (XmlRpcException e) {
			e.printStackTrace();
			return false;
		}
		
	}

}
